package start.spring.basic.job.job.jobthread;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.jboss.logging.MDC;

import lombok.extern.slf4j.Slf4j;
import start.spring.basic.constant.CommonConstant;
import start.spring.basic.dynamic.SpringJdbc;
import start.spring.basic.job.job.service.IJobService;
import start.spring.basic.job.quartz.QuartzConstant;
import start.spring.basic.log.LogConstant;
import start.spring.basic.util.common.StringUtil;

/**
 * ****************************************************************************
 * 自动任务执行器基类，提供公共的自动任务方法
 *
 * @author(作者)：xuyongyun	
 * @date(创建日期)：2018年8月30日
 ******************************************************************************
 */
@Slf4j
public class BaseThread extends Thread {
	
	/**
	 * 线程运行中
	 */
	protected final String THREAD_STATUS_RUNNING = "1";
	
	/**
	 * 线程执行成功
	 */
	protected final String THREAD_STATUS_SUCC = "2";
	
	/**
	 * 线程执行失败
	 */
	protected final String THREAD_STATUS_FAIL = "3";
	
	/**
	 * 线程名称
	 */
	protected String threadName;
	
	/**
	 * 共同完成任务的线程总数
	 */
	protected int threadCount;
	
	/**
	 * 当前线程在线程组中的排序
	 */
	protected int threadXh;
	
	/**
	 * 共同完成任务的线程批次号
	 */
	protected String pch;
	
	/**
	 * 发起线程执行的job类名，用于更新job完成状态
	 */
	protected String jobClassName;

	/**
	 * 业务处理
	 */
	protected IJobService jobService;
	
	@Override
	public void run() {
		super.run();
	}

	/**
	 * 记录线程开始执行
	 *	
	 * @param dao 数据源
	 * @param pch 线程批次号
	 * @param threadName 带编号线程名称
	 * @since           1.0
	 */
	public void reThreadStart(SpringJdbc dao) {
		
		//当前线程唯一标志
		String traceId = StringUtil.getUuid();
		MDC.put(LogConstant.REQUEST_KEY_TRACEID, traceId);
		
		//随机延时一小段时间
		randomSleep();
		
		//记录线程开始执行
		//mysql
		String sql = "insert into GG_THREAD_EXEC(PCH,THREADNAME,STATUS,KSSJ,THREADID)values(?,?,?,now(),?)";
		String[] prams = {pch,threadName,THREAD_STATUS_RUNNING,traceId};
		dao.excute(sql, prams);
	}

	/**
	 * 记录线程的状态为结束
	 * 如果当前线程是本批次最后一个执行完成的线程，则更新job状态为已完成
	 *	
	 * @param dao 数据源
	 * @param threadName 线程名称
	 * @param threadCount 本批次线程总数
	 * @param pch 批次号
	 * @param jobClassName 发起线程的job类名
	 * @param threadStatus 线程最终执行状态
	 * @param errMsg 错误信息
	 * @param jobService job的公共处理方法
	 * 
	 * @since           1.0
	 */
	public void reThreadEnd(SpringJdbc dao,String threadStatus, String errMsg) {
		//随机延时一小段时间
		randomSleep();
		
		String msg = "";
		if(errMsg.length()>CommonConstant.ERRMSG_MAX_LENGTH) {
			msg = errMsg.substring(0, CommonConstant.ERRMSG_MAX_LENGTH);
		}else {
			msg = errMsg;
		}
		
		//记录当前线程的结束状态
		//mysql
		String sql = "update GG_THREAD_EXEC t set t.status = ?,t.jssj = now(),t.cwxx = ? where t.pch = ? and t.threadname = ?";
		String[] prams = {threadStatus,msg,pch,threadName};
		dao.excute(sql, prams);
		
		//查询所有已完成的线程数量
		sql = "select count(*) threadnum,'2' status from GG_THREAD_EXEC t where t.pch = ? and t.status = '2' "
				+ "union all select count(*) threadnum,'3' status from GG_THREAD_EXEC t where t.pch = ? and t.status = '3'";
		prams = new String[] {pch,pch};
		
		List<Map<String, Object>> execResultList = dao.query(sql, prams);
		
		//统计已完成线程数量的分布情况
		int succCount = 0;
		int failCount = 0;
		
		if(execResultList!=null&&!execResultList.isEmpty()) {
			for(int i=0;i<execResultList.size();i++) {
				Map<String, Object> tmpMap = execResultList.get(i);
				String status = StringUtil.trimObject(tmpMap.get("STATUS"), "");
				int threadnum = Integer.parseInt(StringUtil.trimObject(tmpMap.get("THREADNUM"), "0"));
				if(THREAD_STATUS_SUCC.equals(status)) {
					succCount = threadnum;
				}else if(THREAD_STATUS_FAIL.equals(status)) {
					failCount = threadnum;
				}
			}
		}
		
		int endCount = succCount + failCount;
		
		if(endCount<threadCount) {
			log.debug(pch + "对应的线程组未全部完成！");
		}else {
			//本组线程均执行完毕
			String jobStatus = QuartzConstant.JOB_STATUS_SUCC;
			if(failCount>0) {
				//存在执行失败的线程
				jobStatus = QuartzConstant.JOB_STATUS_FAIL;
				
				//查询某一个线程的错误信息
				sql = "select t.cwxx from GG_THREAD_EXEC t where t.pch = ?";
				prams = new String[] {pch};
				Map<String, Object> tmpMap = dao.getOne(sql, prams);
				if(tmpMap!=null) {
					errMsg = StringUtil.trimObject(tmpMap.get("CWXX"), "");
				}
			}
			
			jobService.reJobEnd(jobStatus, errMsg, jobClassName, pch);
		}
		MDC.clear();
	}
	
	/**
	 * 线程随机休眠一小段时间，防止并发线程同时完成导致的job完成状态统计不正确
	 *	
	 * @since           1.0
	 */
	private void randomSleep() {
		  int time = (int) (Math.random()*400 + 100);
		  try {
			TimeUnit.MILLISECONDS.sleep(time);
		} catch (InterruptedException e) {
			e.printStackTrace();
			Thread.currentThread().interrupt();
		}
	}
	
	public String getThreadName() {
		return threadName;
	}
	
	public void setThreadName(String threadName) {
		this.threadName = threadName;
	}
	
	public int getThreadCount() {
		return threadCount;
	}

	public void setThreadCount(int threadCount) {
		this.threadCount = threadCount;
	}

	public int getThreadXh() {
		return threadXh;
	}

	public void setThreadXh(int threadXh) {
		this.threadXh = threadXh;
	}

	public String getPch() {
		return pch;
	}
	
	public void setPch(String pch) {
		this.pch = pch;
	}
	
	public String getJobClassName() {
		return jobClassName;
	}

	public void setJobClassName(String jobClassName) {
		this.jobClassName = jobClassName;
	}

	public IJobService getJobService() {
		return jobService;
	}

	public void setJobService(IJobService jobService) {
		this.jobService = jobService;
	}
}
